package com.hmall.item.service.impl;
import com.hmall.item.mapper.ItemFreezeMapper;
import com.hmall.item.mapper.ItemMapper;
import com.hmall.item.pojo.Item;
import com.hmall.item.pojo.ItemFreeze;
import com.hmall.item.service.ItemTCCService;
import io.seata.core.context.RootContext;
import io.seata.rm.tcc.api.BusinessActionContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Slf4j
public class ItemTCCServiceImpl implements ItemTCCService {

    @Autowired
    private ItemMapper itemMapper;

    @Autowired
    private ItemFreezeMapper itemFreezeMapper;

    /**
     * 库存消减
     * 1 扣减item表可用库存
     * 2 记录冻结库存和事务状态到item_freeze表
     * @param itemId
     * @param num
     *
     */
    @Override
   // @Transactional
    public void deduct(Long itemId, int num) {
        String xid = RootContext.getXID();
        //解决业务悬挂问题
        //通过事务Id查询冻结表，如果存在记录，说明cancel已经执行过了，拒绝业务
        ItemFreeze itemFreeze = itemFreezeMapper.selectById(xid);
        if (itemFreeze != null) {
            //cancel已经执行过了，拒绝业务
            return;
        }
        //1. 扣减库存
        itemMapper.deduct(itemId,num);
        log.debug("扣减库存成功: {},itemId={}", xid, itemId);
        //2. 添加冻结记录
        ItemFreeze freeze = new ItemFreeze();
        freeze.setFreezeNum(num);
        freeze.setState(ItemFreeze.State.TRY);
        freeze.setXid(xid);
        freeze.setItemId(itemId);
        itemFreezeMapper.insert(freeze);
        log.debug("冻结库存成功! {},itemId={}", xid, itemId);
        //3. 添加本地事务控制
    }

    /**
     * 确认业务，根据xid删除item_freeze表的冻结记录
     * @param ctx
     * @return
     */
    @Override
    public boolean confirm(BusinessActionContext ctx) {
        //1. 获取事务Id
        String xid = ctx.getXid();
        log.debug("进入confirm: {}", xid);
        //2. 通过事务Id删除数据
        int count = itemFreezeMapper.deleteById(xid);
        log.debug("删除冻结记录 {},count={}",xid,count);
        return 1==count;
    }

    /**
     * 撤消回滚，需要把冻结库存还原
     * 1 修改account_freeze表，冻结库存为0，state为2
     * 2 修改account表，恢复可用库存
     * @param ctx
     * @return
     */
    @Override
    @Transactional
    public boolean cancel(BusinessActionContext ctx) {
        Long itemId= Long.valueOf(ctx.getActionContext("itemId").toString());
        //1. 获取事务Id
        String xid = ctx.getXid();
        //2. 查询冻结记录
        ItemFreeze freeze = itemFreezeMapper.selectById(xid);
        //解决空回滚方法
        if (freeze == null) {
            //为空，证明deduct（try）没有执行，需要空回滚，需要添加记录来冻结表中，表示取消
            freeze=new ItemFreeze();
            freeze.setFreezeNum(0);
            freeze.setState(ItemFreeze.State.CANCEL);
            freeze.setXid(xid);
            freeze.setItemId(itemId);
            itemFreezeMapper.insert(freeze);
            return true;
        }
        //幂等处理
        if (ItemFreeze.State.CANCEL == freeze.getState().intValue()) {
            //状态为cancel，说明已经处理过一次，无需重复处理
            return true;
        }
        //3. 回滚库存
        //String userId = ctx.getActionContext("userId").toString();
        log.debug("开始回滚库存: {},itemId={}", xid, itemId);
        itemMapper.refund(itemId, freeze.getFreezeNum());
        //4. 更新冻结库存为0，且更新状态为cancel
        freeze = new ItemFreeze();
        freeze.setFreezeNum(0);
        freeze.setState(ItemFreeze.State.CANCEL);
        freeze.setXid(xid);
        int count = itemFreezeMapper.updateById(freeze);
        log.debug("回滚-更新冻结状态：{}, userId={},count={}", xid, itemId,count);
        //5. 本地事务控制
        return count==1;
    }
}